<?php

/**
*	
*		Phiên bản: 1.2
*		Ngày: 8-3-2011
*		Tên lớp: PG_checkout
*		Chức năng: Tích hợp thanh toán qua API
*			- Xây dựng URL chuyển thông tin tới Soha Payment để xử lý việc thanh toán cho merchant site.
*			- Xác thực tính chính xác của thông tin đơn hàng được gửi về từ Soha Payment.
*		
**/

define('PG_URL_ROOT', 'https://sohapay.com/');

class PG_checkout 
{
	// URL checkout của Soha Payment
	private $pg_url = 'payment.php';

	// URL checkout của Soha Payment
	private $pg_url_query = 'payment_query.php';
	
	// URL embed của Soha Payment
	private $pg_url_embed = 'merchant_popup.php';
	
	// Mã merchante site 
	private $merchant_site_code = 'u101';	// Biến này được Soha Payment cung cấp cho merchant site
	
	// Mật khẩu bảo mật
	private $secure_secret= 'b99cb05b063d4f9acf7a'; // Biến này được Soha Payment cung cấp cho merchant site
    
    function __construct($site_code="", $site_secure=""){         
        if (!empty($site_code) && !empty($site_secure)){
            $this->merchant_site_code = $site_code;
            $this->secure_secret = $site_secure;
        }
        $this->pg_url = PG_URL_ROOT . $this->pg_url;
        $this->pg_url_query = PG_URL_ROOT . $this->pg_url_query;
        $this->pg_url_embed = PG_URL_ROOT . $this->pg_url_embed;
    }
	
	//Hàm xây dựng url, trong đó có tham số mã hóa (còn gọi là public key)
	public function buildCheckoutUrl($return_url, $transaction_info, $order_code, $price, $order_email, $order_mobile='')
	{
		
		// Mảng các tham số chuyển tới Soha Payment
		$arr_param = array(
			'site_code'			=>	strval($this->merchant_site_code),
			'return_url'		=>	strval($return_url),
			'transaction_info'	=>	strval($transaction_info),
			'order_code'		=>	strval($order_code),
			'price'				=>	strval($price),	
			'order_email'		=>	strval($order_email),
			'order_mobile'		=>	strval($order_mobile)
		);
		
		ksort($arr_param);
		/* Bước 2. Kiểm tra  biến $redirect_url xem có '?' không, nếu không có thì bổ sung vào*/
		$redirect_url = $this->pg_url;
		if (strpos($redirect_url, '?') === false)
		{
			$redirect_url .= '?';
		}
		else if (substr($redirect_url, strlen($redirect_url)-1, 1) != '?' && strpos($redirect_url, '&') === false)
		{
			// Nếu biến $redirect_url có '?' nhưng không kết thúc bằng '?' và có chứa dấu '&' thì bổ sung vào cuối
			$redirect_url .= '&';			
		}
				
		/* Bước 3. tạo url*/
		$first = true;
		$secure_code = $this->secure_secret;
		foreach ($arr_param as $key=>$value)
		{
			if ($first == true){
				$redirect_url .= urlencode($key) . '=' . urlencode($value);
				$first = false;
			}
			else
				$redirect_url .= '&' . urlencode($key) . '=' . urlencode($value);
			
			$secure_code .= $value;
		}
		
		if (strlen($secure_code) > 0) {
		    $redirect_url .= "&secure_hash=" . strtoupper(md5($secure_code));
		}
		
		return $redirect_url;
	}
	
	//Hàm xây dựng url, trong đó có tham số mã hóa (còn gọi là public key)
	public function buildEmbedUrl($inputParam = array())
	{
		
		// Mảng các tham số chuyển tới Soha Payment
    $crURL = (!empty($_SERVER['HTTPS'])) ? "https://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'] : "http://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
		$arr_param = array(
			'site_code'			=>	strval($this->merchant_site_code),
			'return_url'		=>	isset($inputParam['return_url'])?strval($inputParam['return_url']):$crURL,
			'transaction_info'	=>	isset($inputParam['transaction_info'])?strval($inputParam['transaction_info']):'',
			'order_code'		=>	isset($inputParam['order_code'])?strval($inputParam['order_code']):time().'_'.$this->randomcode(8),
			'price'				=>	isset($inputParam['price'])?strval($inputParam['price']):0,
			'order_email'		=>	isset($inputParam['order_email'])?strval($inputParam['order_email']):'',
			'order_mobile'		=>	isset($inputParam['order_mobile'])?strval($inputParam['order_mobile']):'',
			'order_product_title'	=>  isset($inputParam['order_product_title'])?strval($inputParam['order_product_title']):'Giao dịch thanh toán tiền',
			'order_product_id'	=>  isset($inputParam['order_product_id'])?intval($inputParam['order_product_id']):0,
			'order_product_unit'=>  isset($inputParam['order_product_unit'])?strval($inputParam['order_product_unit']):'sản phẩm',
			'order_number_total'=>  isset($inputParam['order_number_total'])?intval($inputParam['order_number_total']):10,
			'order_number_max'	=>  isset($inputParam['order_number_max'])?intval($inputParam['order_number_max']):10,
			'order_number_min'	=>  isset($inputParam['order_number_min'])?intval($inputParam['order_number_min']):1,
			'order_ship'		=>  isset($inputParam['order_ship'])?intval($inputParam['order_ship']):0,
			'order_ship_fee'	=>  isset($inputParam['order_ship_fee'])?intval($inputParam['order_ship_fee']):0,
			'order_ship_type'	=>  isset($inputParam['order_ship_type'])?intval($inputParam['order_ship_type']):3,
			'order_cod_fee'		=>  isset($inputParam['order_cod_fee'])?intval($inputParam['order_cod_fee']):0,
			'order_cod_type'	=>  isset($inputParam['order_cod_type'])?intval($inputParam['order_cod_type']):1,
			'payment_type'		=> 	isset($inputParam['payment_type'])?strval($inputParam['payment_type']):'|1|',
			'embed_type'		=> 	isset($inputParam['embed_type'])?strval($inputParam['embed_type']):'popup'
		);
		
		ksort($arr_param);

		/* Bước 2. Kiểm tra  biến $redirect_url xem có '?' không, nếu không có thì bổ sung vào*/
		$redirect_url = $this->pg_url_embed;
		if (strpos($redirect_url, '?') === false)
		{
			$redirect_url .= '?';
		}
		else if (substr($redirect_url, strlen($redirect_url)-1, 1) != '?' && strpos($redirect_url, '&') === false)
		{
			// Nếu biến $redirect_url có '?' nhưng không kết thúc bằng '?' và có chứa dấu '&' thì bổ sung vào cuối
			$redirect_url .= '&';			
		}
				
		/* Bước 3. tạo url*/
		$first = true;
		$secure_code = $this->secure_secret;
		foreach ($arr_param as $key=>$value)
        if (($value!='') && ($value!='0'))
		{
			if ($first == true){
				$redirect_url .= urlencode($key) . '=' . urlencode($value);
				$first = false;
			}
			else
				$redirect_url .= '&' . urlencode($key) . '=' . urlencode($value);
			
			$secure_code .= $value;
		}
		
		if (strlen($secure_code) > 0) {
		    $redirect_url .= "&secure_hash=" . strtoupper(md5($secure_code));
		}
		
		return $redirect_url;
	}
  
  /* Hàm xây dựng mã nhúng */
  public function buildEmbedHTML($params=array()){
    $url = $this->buildEmbedUrl($params);
    return sprintf('<a class="mcpBtn" href="%s"><img src="%simages/btn/muangay_sohapay_orange.png" style="margin:5px 0px 0px 0px;" /></a>', $url, PG_URL_ROOT);
  }
	
	/*Hàm thực hiện xác minh tính đúng đắn của các tham số trả về từ Soha Payment*/
	
	public function verifyReturnUrl()
	{
		$secure_hash = $_GET['secure_code'];
		unset($_GET['secure_code']);
	
		$param['transaction_info']	= $_GET['transaction_info'];
		$param['order_code'] 		= $_GET['order_code'];
		$param['order_email'] 		= $_GET['order_email'];
		$param['order_session'] 	= $_GET['order_session'];
		$param['price'] 			= $_GET['price'];
		$param['site_code'] 		= $_GET['site_code'];
		$param['response_code'] 	= $_GET['response_code'];
		$param['response_message'] 	= $_GET['response_message'];
		$param['payment_type'] 		= $_GET['payment_type'];
		$param['payment_time'] 		= $_GET['payment_time'];
		$param['error_text'] 		= $_GET['error_text'];
	
		ksort($param);
		$md5HashData = $this->secure_secret;	
	
	    foreach($param as $key => $value) {
	        if ($key != "secure_code" or strlen($value) > 0) {
	            $md5HashData .= urldecode($value);
	        }
	    }
	    
	    if (strtoupper($secure_hash) == strtoupper(md5($md5HashData))) {
	        return TRUE;
	    } else {
	        return FALSE;
	    }
	}
	
	/**
	 * Cap nhat trang thai don hang pending sau khi timeout
	 * @param string $order_code
	 * @param string $command 
	 * 			query: thanh toan bang the Quoc te hoac the Noi dia
	 * 			queryMobileCard: thanh toan bang the cao dien thoai
	 * @return string
	 */
	public function queryOrderStatus($order_code, $command='query'){
		// Mảng các tham số chuyển tới Soha Payment
		$arr_param = array(
			'site_code'			=>	strval($this->merchant_site_code),
			'order_code'		=>	strval($order_code),
			'command'			=>	$command
		);
		
		ksort($arr_param);
		/* Bước 2. Kiểm tra  biến $redirect_url xem có '?' không, nếu không có thì bổ sung vào*/
		$query_url = $this->pg_url_query;
		if (strpos($query_url, '?') === false)
		{
			$query_url .= '?';
		}
		else if (substr($query_url, strlen($query_url)-1, 1) != '?' && strpos($query_url, '&') === false)
		{
			// Nếu biến $redirect_url có '?' nhưng không kết thúc bằng '?' và có chứa dấu '&' thì bổ sung vào cuối
			$query_url .= '&';			
		}
				
		/* Bước 3. tạo url*/
		$first = true;
		$secure_code = $this->secure_secret;
		foreach ($arr_param as $key=>$value)
		{
			if ($first == true){
				$query_url .= urlencode($key) . '=' . urlencode($value);
				$first = false;
			}
			else
				$query_url .= '&' . urlencode($key) . '=' . urlencode($value);
			
			$secure_code .= $value;
		}
		
		if (strlen($secure_code) > 0) {
		    $query_url .= "&secure_hash=" . strtoupper(md5($secure_code));
		}
		
		ob_start();
	
		// initialise Client URL object
		$ch = curl_init();
		
		// set the URL of the VPC
		curl_setopt ($ch, CURLOPT_URL, $query_url);
		curl_setopt ($ch, CURLOPT_POST, 0);
		curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
		curl_exec ($ch);
	
		// get response
		$response = ob_get_contents();
		
		// turn output buffering off.
		ob_end_clean();
		
		// close client URL
		curl_close ($ch);

		$map = array();

	    $pairArray = explode("&", $response);
	    foreach ($pairArray as $pair) {
	        $param = explode("=", $pair);
	        $map[urldecode($param[0])] = urldecode($param[1]);
	    }
	    
	    $map['shp_payment_response_description'] = '';
	    if ($map['shp_payment_type']==1) $map['shp_payment_response_description'] = $this->getResponseDescriptionInternational($map['shp_payment_response_code']);
	    else if ($map['shp_payment_type']==2) $map['shp_payment_response_description'] = $this->getResponseDescriptionDomestic($map['shp_payment_response_code']);
	    else if ($map['shp_payment_type']==3) $map['shp_payment_response_description'] = $this->getResponseDescriptionMobileCard($map['shp_payment_response_code']);
	    
	    return $map;
	}
	

	public function doChargeCard($card_code, $card_type, $transaction_info, $order_code, $order_email, $order_mobile){
		// Mảng các tham số chuyển tới Soha Payment
		$arr_param = array(
			'site_code'			=>	strval($this->merchant_site_code),
			'card_code'			=>	strval($card_code),
			'card_type'			=>	strval($card_type), // vinaphone or mobifone
			'transaction_info'	=>	strval($transaction_info),
			'order_code'		=>	strval($order_code),
			'order_email'		=>	strval($order_email),
			'order_mobile'		=>	strval($order_mobile),
			'command'			=>	'doChargeMobileCard'
		);
		
		ksort($arr_param);
		/* Bước 2. Kiểm tra  biến $redirect_url xem có '?' không, nếu không có thì bổ sung vào*/
		$query_url = $this->pg_url_query;
		if (strpos($query_url, '?') === false)
		{
			$query_url .= '?';
		}
		else if (substr($query_url, strlen($query_url)-1, 1) != '?' && strpos($query_url, '&') === false)
		{
			// Nếu biến $redirect_url có '?' nhưng không kết thúc bằng '?' và có chứa dấu '&' thì bổ sung vào cuối
			$query_url .= '&';			
		}
				
		/* Bước 3. tạo url*/
		$first = true;
		$secure_code = $this->secure_secret;
		foreach ($arr_param as $key=>$value)
		{
			if ($first == true){
				$query_url .= urlencode($key) . '=' . urlencode($value);
				$first = false;
			}
			else
				$query_url .= '&' . urlencode($key) . '=' . urlencode($value);
			
			$secure_code .= $value;
		}
		
		if (strlen($secure_code) > 0) {
		    $query_url .= "&secure_hash=" . strtoupper(md5($secure_code));
		}
		
		ob_start();
	
		// initialise Client URL object
		$ch = curl_init();
	
		// set the URL of the VPC
		curl_setopt ($ch, CURLOPT_URL, $query_url);
		curl_setopt ($ch, CURLOPT_POST, 0);
		curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
		curl_exec ($ch);
	
		// get response
		$response = ob_get_contents();
		
		// turn output buffering off.
		ob_end_clean();
		
		// close client URL
		curl_close ($ch);

		$map = array();
		$response = substr($response, 1);

	    $pairArray = explode("&", $response);
	    foreach ($pairArray as $pair) {
	        $param = explode("=", $pair);
	        $map[urldecode($param[0])] = urldecode($param[1]);
	    }
	    
	    $map['shp_payment_response_description'] = $this->getResponseDescriptionMobileCard($map['response_code']);
	    
	    return $map;
	}
	
	public function getResponseDescriptionInternational($responseCode) {
	    switch ($responseCode) {
	        case "0" : $result = "Giao dịch thành công"; break;
	        case "?" : $result = "Tình trạng giao dịch không xác định"; break;
	        case "1" : $result = "Lỗi không xác định"; break;
	        case "2" : $result = "Ngân hàng từ tối giao dịch"; break;
	        case "3" : $result = "Không có trả lời từ Ngân hàng"; break;
	        case "4" : $result = "Thẻ hết hạn"; break;
	        case "5" : $result = "Số dư không đủ để thanh toán"; break;
	        case "6" : $result = "Lỗi giao tiếp với Ngân hàng"; break;
	        case "7" : $result = "Lỗi Hệ thống máy chủ Thanh toán"; break;
	        case "8" : $result = "Loại giao dịch không được hỗ trợ"; break;
	        case "9" : $result = "Ngân hàng từ chối giao dịch (không liên hệ với Ngân hàng)"; break;
	        case "A" : $result = "giao dịch Aborted"; break;
	        case "B" : $result = "Bị chặn do có rủi ro giả mạo"; break;
	        case "C" : $result = "giao dịch bị hủy bỏ"; break;
	        case "D" : $result = "giao dịch hoãn lại đã được nhận và đang chờ xử lý"; break;
	        case "E" : $result = "Referred"; break;
	        case "F" : $result = "3D Secure xác thực không thành công"; break;
	        case "I" : $result = "Card Security Code xác minh không thành công"; break;
	        case "L" : $result = "Mua sắm giao dịch đã bị khoá (Xin vui lòng thử lại sau giao dịch)"; break;
	        case "N" : $result = "Chủ thẻ không ghi danh vào chương trình xác thực"; break;
	        case "P" : $result = "giao dịch đã được nhận bởi các Adaptor Thanh toán và đang được xử lý"; break;
	        case "R" : $result = "giao dịch đã không được xử lý - Đã đạt đến giới hạn của những cố gắng thử lại cho phép"; break;
	        case "S" : $result = "SessionID bị trùng (OrderInfo)"; break;
	        case "T" : $result = "Địa chỉ xác minh không đúng"; break;
	        case "U" : $result = "Card Security Code không đúng"; break;
	        case "V" : $result = "Địa chỉ xác minh và Card Security Code không đúng"; break;
	        case "9999": $result = "Giao dịch có rủi ro giả mạo";break;
	        case "PG": $result = "Không tồn tại giao dịch trên hệ thống";break;
	        default  : $result = "Không thể xác định"; 
	    }
	    return $result;
	}
	
	public function getResponseDescriptionDomestic($responseCode){
		switch ($responseCode) {
	        case "0" : $result = "Giao dịch thành công"; break;
	        case "1" : $result = "Ngân hàng từ chối giao dịch"; break;
	        case "3" : $result = "Mã đơn vị không tồn tại"; break;
	        case "4" : $result = "Không đúng access code"; break;
	        case "5" : $result = "Số tiền không hợp lệ"; break;
	        case "6" : $result = "Mã tiền tệ không tồn tại"; break;
	        case "7" : $result = "Lỗi không xác định"; break;
	        case "8" : $result = "Số thẻ không đúng"; break;
	        case "9" : $result = "Tên chủ thẻ không đúng"; break;
	        case "10" : $result = "Thẻ hết hạn/Thẻ bị khóa"; break;
	        case "11" : $result = "Thẻ chưa đăng ký sử dụng dịch vụ thanh toán trực tuyến."; break;
	        case "12" : $result = "Ngày phát hành/Hết hạn không đúng"; break;
	        case "13" : $result = "Vượt quá hạn mức thanh toán"; break;
	        case "21" : $result = "Số dư không đủ để thanh toán"; break;
	        case "99" : $result = "Người sử dụng hủy giao dịch"; break;
	        case "100" : $result = "Không nhập thông tin thẻ/ Hủy giao dịch thanh toán"; break;
	        case "PG": $result = "Không tồn tại giao dịch trên hệ thống";break;
	        default  : $result = "Không thể xác định";
		}
		return $result;
	}
	
	public function getResponseDescriptionMobileCard($responseCode){
		switch ($responseCode) {
	        case "1" : $result = "Giao dịch thành công"; break;
	        case "-1" : $result = "Thẻ đã sử dụng (Mobifone)"; break;
	        case "-2" : $result = "Thẻ đã khoá (Mobifone)"; break;
	        case "-3" : $result = "Thẻ đã hết hạn sử dụng (Mobifone)"; break;
	        case "-4" : $result = "Thẻ chưa kích hoạt (Mobifone)"; break;
	        case "-10" : $result = "Mã thẻ không đúng định dạng (Mobifone)"; break;
	        case "-12" : $result = "Thẻ không tồn tại (Mobifone)"; break;
	        case "-99" : $result = "Lỗi hệ thống nạp của Mobile"; break;
	        case "0" : $result = "Lỗi khác (Mobifone)"; break;
	        case "2" : $result = "Không login sử dụng các hàm charge"; break;
	        case "3" : $result = "Lỗi hệ thống của VDCO"; break;
	        case "4" : $result = "Thẻ không sử dụng được (lỗi chung cho Vinaphone)"; break;
	        case "5" : $result = "Thực hiện sai 5 lần liên tiếp"; break;
	        case "6" : $result = "Thực hiện lệnh logout không thành công"; break;
	        case "8" : $result = "Charge thẻ bị lỗi hệ thống. Lỗi này cần kiểm soát và đối soát"; break;
	        case "9" : $result = "Thông tin partner không đúng"; break;
	        case "10" : $result = "Sai format thông tin email hoặc mobile"; break;
	        default  : $result = "Không thể xác định";
		}
		return $result;
	}
  
  private function randomcode($len=8){
  	$code = $lchar = NULL;
  	for( $i=0; $i<$len; $i++ )
    	{
  	  	$char = chr(rand(48,122));
  	  	while( !ereg("[a-zA-Z0-9]", $char) )
      	{
  		    if( $char == $lchar ) continue;
  		    $char = chr(rand(48,90));
  	  	}
  	  	$pass .= $char;
  	  	$lchar = $char;
  	}
  	return $pass;
  }
}
?>